<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../polymer.html">
  <link rel="import" href="templatizer-elements.html">
</head>
<body>

<script>

  suite('templatizer client and template separate', function() {
    /* global childA childB */

    var host;

    setup(function() {
      host = document.createElement('x-host');
      document.body.appendChild(host);
    });

    teardown(function() {
      document.body.removeChild(host);
    });

    test('stamped with initial data', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      assert.equal(childA.outerProp, 'outerProp');
      assert.equal(childA.outerObj, host.outerObj);
      assert.equal(childA.outerObjProp, 'outerObj.prop');
      assert.equal(childA.prop, 'prop-a');
      assert.equal(childA.obj, host.objA);
      assert.equal(childA.objProp, 'objA.prop');
    });

    test('host properties propagated in', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      host.outerProp = 'outerProp++';
      assert.equal(childA.outerProp, 'outerProp++');
      host.outerObj = { prop: 'outerObj++.prop' };
      assert.equal(childA.outerObj, host.outerObj);
      assert.equal(childA.outerObjProp, 'outerObj++.prop');
    });

    test('host paths propagated in', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      sinon.spy(childA, 'outerObjChanged');
      host.set('outerObj.prop', 'outerObj.prop++');
      assert.equal(childA.outerObjProp, 'outerObj.prop++');
      assert.isTrue(childA.outerObjChanged.calledOnce);
      assert.equal(childA.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');
      assert.equal(childA.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');
    });

    test('host properties propagated out', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      childA.outerProp = 'outerProp++';
      assert.equal(host.outerProp, 'outerProp++');
      childA.outerObj = { prop: 'outerObj++.prop' };
      assert.equal(host.outerObj.prop, 'outerObj++.prop');
    });

    test('host paths propagated out', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      sinon.spy(host, 'outerObjChanged');
      childA.set('outerObj.prop', 'outerObj.prop++');
      assert.equal(host.outerObj.prop, 'outerObj.prop++');
      assert.isTrue(host.outerObjChanged.calledOnce);
      assert.equal(host.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');
      assert.equal(host.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');
    });

    test('instance properties propagated in', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      host.propA = 'prop-a++';
      assert.equal(childA.prop, 'prop-a++');
      host.objA = { prop: 'objA++.prop' };
      assert.equal(childA.obj, host.objA);
      assert.equal(childA.objProp, 'objA++.prop');
    });

    test('instance paths propagated in', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      sinon.spy(childA, 'objChanged');
      host.set('objA.prop', 'objA.prop++');
      assert.equal(childA.obj.prop, 'objA.prop++');
      assert.isTrue(childA.objChanged.calledOnce);
      assert.equal(childA.objChanged.getCall(0).args[0].path, 'obj.prop');
      assert.equal(childA.objChanged.getCall(0).args[0].value, 'objA.prop++');
    });

    test('instance properties propagated out', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      childA.prop = 'prop-a++';
      assert.equal(host.propA, 'prop-a++');
      childA.obj = { prop: 'objA++.prop' };
      assert.equal(host.objA.prop, 'objA++.prop');
    });

    test('instance paths propagated out', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      sinon.spy(host, 'objAChanged');
      childA.set('obj.prop', 'objA.prop++');
      assert.equal(host.objA.prop, 'objA.prop++');
      assert.isTrue(host.objAChanged.calledOnce);
      assert.equal(host.objAChanged.getCall(0).args[0].path, 'objA.prop');
      assert.equal(host.objAChanged.getCall(0).args[0].value, 'objA.prop++');
    });

    test('outer & inner props conflict', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      assert.equal(childA.conflict, 'bar');
      host.set('outerInnerConflict.prop', 'foo');
      assert.equal(childA.conflict, 'bar');
    });

  });

  suite('templatizer client and template same element (template extension)', function() {

    var host;

    setup(function() {
      host = document.createElement('x-host');
      document.body.appendChild(host);
    });

    teardown(function() {
      document.body.removeChild(host);
    });

    test('stamped with initial data', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      assert.equal(childB.outerProp, 'outerProp');
      assert.equal(childB.outerObj, host.outerObj);
      assert.equal(childB.outerObjProp, 'outerObj.prop');
      assert.equal(childB.prop, 'prop-b');
      assert.equal(childB.obj, host.objB);
      assert.equal(childB.objProp, 'objB.prop');
    });

    test('host properties propagated in', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      host.outerProp = 'outerProp++';
      assert.equal(childB.outerProp, 'outerProp++');
      host.outerObj = { prop: 'outerObj++.prop' };
      assert.equal(childB.outerObj, host.outerObj);
      assert.equal(childB.outerObjProp, 'outerObj++.prop');
    });

    test('host paths propagated in', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      sinon.spy(childB, 'outerObjChanged');
      host.set('outerObj.prop', 'outerObj.prop++');
      assert.equal(childB.outerObjProp, 'outerObj.prop++');
      assert.isTrue(childB.outerObjChanged.calledOnce);
      assert.equal(childB.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');
      assert.equal(childB.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');
    });

    test('host properties propagated out', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      childB.outerProp = 'outerProp++';
      assert.equal(host.outerProp, 'outerProp++');
      childB.outerObj = { prop: 'outerObj++.prop' };
      assert.equal(host.outerObj.prop, 'outerObj++.prop');
    });

    test('host paths propagated out', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      sinon.spy(host, 'outerObjChanged');
      childB.set('outerObj.prop', 'outerObj.prop++');
      assert.equal(host.outerObj.prop, 'outerObj.prop++');
      assert.isTrue(host.outerObjChanged.calledOnce);
      assert.equal(host.outerObjChanged.getCall(0).args[0].path, 'outerObj.prop');
      assert.equal(host.outerObjChanged.getCall(0).args[0].value, 'outerObj.prop++');
    });

    test('instance properties propagated in', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      host.propB = 'prop-b++';
      assert.equal(childB.prop, 'prop-b++');
      host.objB = { prop: 'objB++.prop' };
      assert.equal(childB.obj, host.objB);
      assert.equal(childB.objProp, 'objB++.prop');
    });

    test('instance paths propagated in', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      sinon.spy(childB, 'objChanged');
      host.set('objB.prop', 'objB.prop++');
      assert.equal(childB.obj.prop, 'objB.prop++');
      assert.isTrue(childB.objChanged.calledOnce);
      assert.equal(childB.objChanged.getCall(0).args[0].path, 'obj.prop');
      assert.equal(childB.objChanged.getCall(0).args[0].value, 'objB.prop++');
    });

    test('instance properties propagated out', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      childB.prop = 'prop-b++';
      assert.equal(host.propB, 'prop-b++');
      childB.obj = { prop: 'objB++.prop' };
      assert.equal(host.objB.prop, 'objB++.prop');
    });

    test('instance paths propagated out', function() {
      host.$.templatizee.go();
      assert.ok(childB);
      sinon.spy(host, 'objBChanged');
      childB.set('obj.prop', 'objB.prop++');
      assert.equal(host.objB.prop, 'objB.prop++');
      assert.isTrue(host.objBChanged.calledOnce);
      assert.equal(host.objBChanged.getCall(0).args[0].path, 'objB.prop');
      assert.equal(host.objBChanged.getCall(0).args[0].value, 'objB.prop++');
    });

    test('outer & inner props conflict', function() {
      host.$.templatizer.go();
      assert.ok(childA);
      assert.equal(childA.conflict, 'bar');
      host.set('outerInnerConflict.prop', 'foo');
      assert.equal(childA.conflict, 'bar');
    });

    test('ensure literals are not forwarded to templates', function() {
      assert.notOk(host._propertyEffects[33]);
      assert.notOk(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(host), 33));
    });

    test('ensure undefined is not set on templatizee', function() {
      assert.equal(host.$.templatizee[undefined], undefined);
    });

  });

</script>
</body>
</html>
